﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using DSCop.Core;
using System.IO;

namespace DSCop
{
    class Program
    {
        static void Main(string[] args)
        {
            //TODO: Refactor to provide better support for unit testing
            Console.WriteLine("DSCop - DataStage job analyzer.");
            Console.WriteLine("Send feedback and comments to dscoptool_at_gmail.com");

            CommandArguments arguments;
            try
            {
                CommandLineArgumentsParser argumentsParser = new CommandLineArgumentsParser();
                arguments = argumentsParser.Parse(args);
            }
            catch (CommandArgumentsException cex)
            {
                Console.WriteLine(cex.Message);
                Console.WriteLine("Usage: DSCop Jobs.xml");
                return;
            }

            Console.WriteLine("Loading rules...");
            RulesContainer rulesContainer = new RulesContainer();
            foreach (Lazy<IDSRule, IDSRuleMeta> rule in rulesContainer.Rules)
            {
                bool ignoreRule = CheckIgnoreRule(rule.Metadata.RuleName, arguments.IncludeRules, arguments.ExcludeRules);
                string ignoreMessage = ignoreRule ? " *Ignored" : String.Empty;

                Console.WriteLine(rule.Metadata.RuleName + ignoreMessage);
            }

            Console.WriteLine("Checking job(s)...");


            string dir = Path.GetDirectoryName(arguments.FileName);
            if (String.IsNullOrEmpty(dir))
            {
                dir = Directory.GetCurrentDirectory();
            }
            string[] filesToCheck = Directory.GetFiles(
                Path.GetFullPath(dir),
                Path.GetFileName(arguments.FileName));


            foreach (string fileName in filesToCheck)
            {
                CheckFile(rulesContainer, fileName, arguments.IncludeRules, arguments.ExcludeRules);
            }
        }

        private static bool CheckIgnoreRule(string ruleName, IList<string> includeRules, IList<string> excludeRules)
        {
            bool ignoreRule = (includeRules.Count() > 0 && includeRules.Contains(ruleName) == false)
                || (excludeRules.Count() > 0 && excludeRules.Contains(ruleName));

            return ignoreRule;
        }

        //TODO: Refactor to provide better support for unit testing
        private static void CheckFile(RulesContainer rulesContainer, string fileName,
            IList<string> includeRules, IList<string> excludeRules)
        {
            XDocument loaded = XDocument.Load(fileName);

            //Select all jobs from the provided XML
            var jobList = from job in loaded.Elements().Elements()
                          where job.Name.LocalName.ToUpper() == "JOB"
                          select job;

            foreach (XElement job in jobList)
            {
                Console.WriteLine(DSCopUtil.GetJobName(job));

                foreach (Lazy<IDSRule, IDSRuleMeta> rule in rulesContainer.Rules)
                {
                    bool ignoreRule = CheckIgnoreRule(rule.Metadata.RuleName, includeRules, excludeRules);
                    if (ignoreRule)
                    {
                        continue;
                    }

                    IList<RuleViolation> violations = rule.Value.ValidateJob(job);
                    foreach (var v in violations)
                    {
                        Console.WriteLine("\t " + v.Message);
                    }
                }
            }
        }
    }
}
